package com.zzyang.mybatis.jdbc.cluster;

import com.zzyang.mybatis.jdbc.core.DataSourceSynchronizationManager;
import com.zzyang.mybatis.jdbc.enums.DataSourceType;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.transaction.Transaction;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;


/**
 * 重试，现在只能用主数据源
 *
 * @author zhuoziyang
 * @date 2021/4/10 16:45
 */
public class FailOverCluster implements Cluster {

    @Override
    public Object execute(Invocation invocation) throws Exception {
        Object result;
        try {
            result = invocation.proceed();
        } catch (Exception e) {
            DataSourceType dataSourceType = DataSourceSynchronizationManager.getDataSourceType();
            if (DataSourceType.MASTER.equals(dataSourceType)) {
                throw e;
            }
            //将下次执行的数据源切换成主数据源
            DataSourceSynchronizationManager.setDataSourceType(DataSourceType.MASTER);

            //获取事务，这个事务是交由spring管理的事务
            //需要将 Connection 设置为null，因为如果 Connection 不是null，就不会从数据源中重新获取连接，也就无法换数据源
            Executor executor = (Executor) invocation.getTarget();
            Transaction transaction = executor.getTransaction();
            transaction.close();
            Field field = transaction.getClass().getDeclaredField("connection");
            ReflectionUtils.makeAccessible(field);
            ReflectionUtils.setField(field, transaction, null);

            result = invocation.proceed();
        }
        return result;
    }

}
